0.1 Overview

In this weeks assignment we will show how to create interactive plots using the library called Plotly.
Plotly is a robust graphing library which will allow us to display interactive, dynamic charts. Unlike static charts, interactive graphs can allow us to convey much more information to a viewer in a more engaging matter. The goal is to display data in such a way that the user can easily interpret any patterns or correlations.

0.2 Data Transformation Review

In last week’s assignment, it was shown how to do various data transformations using many data sets. For this weeks graphs, the data source will be re-using the final data set from week 5.
Recall the structure of the dataset, visualized below:

      Country Year Income life_expectancy region population
1 Afghanistan 1800    603            28.2   Asia    3280000
2 Afghanistan 1801    603            28.2   Asia    3280000
3 Afghanistan 1802    603            28.2   Asia    3280000
4 Afghanistan 1803    603            28.2   Asia    3280000
5 Afghanistan 1804    603            28.2   Asia    3280000
6 Afghanistan 1805    603            28.2   Asia    3280000

If you are unfamiliar with how we got this data set, it is encouraged to review the data transformation sections of week 5.
Simply put, our dataset has information relating to a country for a given year. We will show how to interactively visualize this data set, as opposed to the static charts from last week.

0.3 Interactive Plot - 2015 Data

Our first graph will convey the following information:

  1. A scatter plot showing the relation of life expectancy vs income.
  2. The size of a given dot is proportional to it’s population size.
  3. Hover text will appear over a given point which will display the country name and population size.
  4. Appropriate use of color and transparency for viewing ease.

For this graph, we will analyze data only from the year 2015. We can extract this information via the following code:

subset_2015 <- subset(initial_data, Year == 2015)

The resulting data frame only has 2015 data:

         Country Year Income life_expectancy region population
216  Afghanistan 2015   1750            57.9   Asia   33700000
435      Albania 2015  11000            77.6 Europe    2920000
654      Algeria 2015  13700            77.3 Africa   39900000
873      Andorra 2015  46600            82.5 Europe      78000
1092      Angola 2015   6230            64.0 Africa   27900000

Now, let’s view the interactive graph which meets the specifications listed above.

# Create the scatter plot
plot <- plot_ly(data = subset_2015,
                x = ~Income,
                y = ~life_expectancy,
                text = ~paste("Country: ", Country, "<br>Population Size: ", population),
                color = ~Country,
                size = ~population, sizes = c(5, 150), 
                marker = list(opacity = 0.6, line = list(color = 'black', width = 1))) %>%
        layout(title = "Association between Life Expectancy and Income (2015)",
               xaxis = list(title = "Income"),
               yaxis = list(title = "Life Expectancy"),
               hovermode = "closest")

# Show the plot
plot

NOTE: the proportional size of the point and transparency levels were chosen via trial and error. Also, hovermode being set to closest allows the user to easily view country metadata without the cursor being exactly on a given marker. This is helpful because some dots are quite small.

0.4 Narrative - 2015 Data

The interactive graph has all the features we discussed. This allows us to easily distinguish which countries have the highest population. We can clearly see India, China, and the USA having very large populations based on the size of their individual marker. It is also easy to see that Japan, Switzerland, and Singapore all have the highest life expectancy. Qatar has, by far, the most amount of avg income per person; it must be nice to live there. Interestingly enough, there does not seem to be a correlation between the amount of income an individual makes for a given country, and the life expectancy. However, it is interesting to note that, generally speaking, the African countries have the lowest life expectancy, while the Asian countries seem to have the highest.

0.5 Animated Graph

In this next section we will demonstrate how to show an animation for scatter plots. We will use our original data set with all years up to 1950*, and cycle through each year to see how the data changes over time.

*Note: we include up to 1950 because the income starts to exponentially increase after those years. This causes for a very skewed animation for the first 150 years.

The animated graph will have the following specifications:

  1. Cycle through each year from 1800 to 1950.
  2. Highlight the relationship between life expectancy and population size.
  3. Use a custom, color-blind friendly color palette.
  4. Have the size of a given marker proportional to the population size.
  5. Provide additional metadata when hovering over a marker.

The code is very similar to the previous interactive graph, with the following additions:

  • A much larger input data set.
  • Add the binding for custom colors
  • Cycle through the year

Please view the code & animated plot below:

up_to_1950 <- subset(initial_data, Year <= 1950)

region_colors <- c("Africa" = "#000000", "Americas"="#E69F00", "Asia"="#56B4E9", "Europe"="#009E73", "Oceania"="#CC79A7");

# Create the animated scatter plot
animated_plot <- plot_ly(data = up_to_1950,
                x = ~Income,
                y = ~life_expectancy,
                # Iterate through each year.
                frame = ~Year,
                text = ~paste("Country: ", Country, "<br>Population Size: ", population),
                color = ~region, 
                # Custom color-blind friendly colos.
                colors = region_colors,
                size = ~population, sizes = c(10, 100), 
                marker = list(opacity = 0.6, line = list(color = 'black', width = 1))) %>%
        layout(title = "Relationship between Life Expectancy and Income Over the Years",
               xaxis = list(title = "Income"),
               yaxis = list(title = "Life Expectancy"),
               hovermode = "closest")

# Show the plot
animated_plot

0.6 Narration - Animated Plot

From 1800-1900 we can see that the life expectancy (~20-40) and income (<20k) really does not change that much for a given region. Of course, there are a couple of exceptions in the late 1800s where a few European countries start to increase their average life expectancy into the mid 50s. What’s really interesting is how the life expectancy starts to dramatically increase in the early 1900’s with the introduction of penicillin and modern medicine. It is no surprise that first world regions are the first to increase their life expectancy as they have access to more doctors and modern medicine than a 3rd world regions.

A fascinating pattern emerges if you examine the life expectancy from 1915 - 1925. The average life expectancy drops for every region by a large margin. This is because of WW1. We see a similar pattern for life expectancy from 1930 - 1950 with WW2. Initially, in the early 1930s, only a few regions lower their life expectancy because of the isolated invasions of Germany. However, by 1944, many regions drop dramatically.

This goes to show that war has quite an effect on life expectancy changes. This makes a lot of practical sense.

LS0tDQp0aXRsZTogIldlZWsgNiAtIEludGVyYWN0aXZpdHkgd2l0aCBQbG90bHkiDQphdXRob3I6ICJKYWNvYiBNYXJ0aW4iDQpkYXRlOiAiV2VzdCBDaGVzdGVyIFVuaXZlcnNpdHkgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgZmlnX3dpZHRoOiA2DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgZmlnX2hlaWdodDogNA0KLS0tDQoNCmBgYHs9aHRtbH0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCmRpdiNUT0MgbGkgew0KICAgIGxpc3Qtc3R5bGU6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOmxpZ2h0Z3JheTsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogICAgY29sb3I6ICM3ODBjMGM7DQp9DQoNCi8qIG1vdXNlIG92ZXIgbGluayAqLw0KZGl2I1RPQyBhOmhvdmVyIHsNCiAgY29sb3I6IHJlZDsNCn0NCg0KLyogdW52aXNpdGVkIGxpbmsgKi8NCmRpdiNUT0MgYTpsaW5rIHsNCiAgY29sb3I6IGJsdWU7DQp9DQoNCg0KDQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtibHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBmb250LXZhcmlhbnQtY2Fwczogbm9ybWFsOw0KfQ0KaDQuYXV0aG9yIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyANCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoMSB7DQogICAgZm9udC1zaXplOiAyNHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgyIHsNCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyANCiAgICBmb250LXNpemU6IDE1cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiB1bnZpc2l0ZWQgbGluayAqLw0KYTpsaW5rIHsNCiAgY29sb3I6IGdyZWVuOw0KfQ0KDQovKiB2aXNpdGVkIGxpbmsgKi8NCmE6dmlzaXRlZCB7DQogIGNvbG9yOiBncmVlbjsNCn0NCg0KLyogbW91c2Ugb3ZlciBsaW5rICovDQphOmhvdmVyIHsNCiAgY29sb3I6IHJlZDsNCn0NCg0KLyogc2VsZWN0ZWQgbGluayAqLw0KYTphY3RpdmUgew0KICBjb2xvcjogeWVsbG93Ow0KfQ0KDQo8L3N0eWxlPg0KYGBgDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0Kb3B0aW9ucyhyZXBvcyA9IGxpc3QoQ1JBTj0iaHR0cDovL2NyYW4ucnN0dWRpby5jb20vIikpDQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoImNvd3Bsb3QiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiY293cGxvdCIpDQogICBsaWJyYXJ5KGNvd3Bsb3QpDQp9DQppZiAoIXJlcXVpcmUoImxhdGV4MmV4cCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJsYXRleDJleHAiKQ0KICAgbGlicmFyeShsYXRleDJleHApDQp9DQppZiAoIXJlcXVpcmUoInBsb3RseSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KICAgbGlicmFyeShwbG90bHkpDQp9DQppZiAoIXJlcXVpcmUoImdhcG1pbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJnYXBtaW5kZXIiKQ0KICAgbGlicmFyeShnYXBtaW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoInBuZyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygicG5nIikgICAgICAgICAgICAgIyBJbnN0YWxsIHBuZyBwYWNrYWdlDQogICAgbGlicmFyeSgicG5nIikNCn0NCmlmICghcmVxdWlyZSgiUkN1cmwiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIlJDdXJsIikgICAgICAgICAgICMgSW5zdGFsbCBSQ3VybCBwYWNrYWdlDQogICAgbGlicmFyeSgiUkN1cmwiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb2xvdXJwaWNrZXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImNvbG91cnBpY2tlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJjb2xvdXJwaWNrZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnaWZza2kiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdpZnNraSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnaWZza2kiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJtYWdpY2siKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm1hZ2ljayIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJtYWdpY2siKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnckRldmljZXMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdyRGV2aWNlcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnckRldmljZXMiKQ0KfQ0KIyMjIGdncGxvdCBhbmQgZXh0ZW5zaW9ucw0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdncGxvdDIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ2FuaW1hdGUiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdnYW5pbWF0ZSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ2FuaW1hdGUiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3JpZGdlcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dyaWRnZXMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dyaWRnZXMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJncmFwaGljcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ3JhcGhpY3MiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ3JhcGhpY3MiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJ0aWR5ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5ciIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICBsaWJyYXJ5KHRpZHlyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJyZXNoYXBlMiIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJyZXNoYXBlMiIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICBsaWJyYXJ5KHJlc2hhcGUyKQ0KfQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANCg0KIyMgT3ZlcnZpZXcNCkluIHRoaXMgd2Vla3MgYXNzaWdubWVudCB3ZSB3aWxsIHNob3cgaG93IHRvIGNyZWF0ZSBpbnRlcmFjdGl2ZSBwbG90cyB1c2luZyB0aGUgbGlicmFyeSBjYWxsZWQgYFBsb3RseWAuIFwNCmBQbG90bHlgIGlzIGEgcm9idXN0IGdyYXBoaW5nIGxpYnJhcnkgd2hpY2ggd2lsbCBhbGxvdyB1cyB0byBkaXNwbGF5IGludGVyYWN0aXZlLCBkeW5hbWljIGNoYXJ0cy4gVW5saWtlIHN0YXRpYyBjaGFydHMsIGludGVyYWN0aXZlIGdyYXBocyBjYW4gYWxsb3cgdXMgdG8gY29udmV5IG11Y2ggbW9yZSBpbmZvcm1hdGlvbiB0byBhIHZpZXdlciBpbiBhIG1vcmUgZW5nYWdpbmcgbWF0dGVyLiBUaGUgZ29hbCBpcyB0byBkaXNwbGF5IGRhdGEgaW4gc3VjaCBhIHdheSB0aGF0IHRoZSB1c2VyIGNhbiBlYXNpbHkgaW50ZXJwcmV0IGFueSBwYXR0ZXJucyBvciBjb3JyZWxhdGlvbnMuIA0KDQojIyBEYXRhIFRyYW5zZm9ybWF0aW9uIFJldmlldw0KSW4gPGEgaHJlZj0iaHR0cHM6Ly9qbWFydGluMTIuZ2l0aHViLmlvL1NUQVQ1NTMvd2Vla181L2phY29iX2Fzc2lnbm1lbnRfNS5odG1sIj5sYXN0IHdlZWsncyBhc3NpZ25tZW50PC9hPiwgaXQgd2FzIHNob3duIGhvdyB0byBkbyB2YXJpb3VzIGRhdGEgdHJhbnNmb3JtYXRpb25zIHVzaW5nIG1hbnkgZGF0YSBzZXRzLiBGb3IgdGhpcyB3ZWVrcyBncmFwaHMsIHRoZSBkYXRhIHNvdXJjZSB3aWxsIGJlIHJlLXVzaW5nIHRoZSBmaW5hbCBkYXRhIHNldCBmcm9tIHdlZWsgNS4NClwNClJlY2FsbCB0aGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhc2V0LCB2aXN1YWxpemVkIGJlbG93OiANCg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KaW5pdGlhbF9kYXRhIDwtIHJlYWQuY3N2KCJqbV9maW5hbF9kYXRhLmNzdiIsIGhlYWRlciA9IFRSVUUpDQpoZWFkKGluaXRpYWxfZGF0YSwgNikNCmBgYA0KDQpJZiB5b3UgYXJlIHVuZmFtaWxpYXIgd2l0aCBob3cgd2UgZ290IHRoaXMgZGF0YSBzZXQsIGl0IGlzIGVuY291cmFnZWQgdG8gcmV2aWV3IHRoZSBgZGF0YSB0cmFuc2Zvcm1hdGlvbmAgc2VjdGlvbnMgb2YgPGEgaHJlZj0iaHR0cHM6Ly9qbWFydGluMTIuZ2l0aHViLmlvL1NUQVQ1NTMvd2Vla181L2phY29iX2Fzc2lnbm1lbnRfNS5odG1sIj53ZWVrIDU8L2E+LiANClwNClNpbXBseSBwdXQsIG91ciBkYXRhc2V0IGhhcyBpbmZvcm1hdGlvbiByZWxhdGluZyB0byBhIGNvdW50cnkgZm9yIGEgZ2l2ZW4geWVhci4gV2Ugd2lsbCBzaG93IGhvdyB0byBpbnRlcmFjdGl2ZWx5IHZpc3VhbGl6ZSB0aGlzIGRhdGEgc2V0LCBhcyBvcHBvc2VkIHRvIHRoZSBzdGF0aWMgY2hhcnRzIGZyb20gbGFzdCB3ZWVrLg0KDQojIyBJbnRlcmFjdGl2ZSBQbG90IC0gMjAxNSBEYXRhDQpPdXIgZmlyc3QgZ3JhcGggd2lsbCBjb252ZXkgdGhlIGZvbGxvd2luZyBpbmZvcm1hdGlvbjoNCg0KMS4gQSBzY2F0dGVyIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb24gb2YgYGxpZmUgZXhwZWN0YW5jeWAgdnMgYGluY29tZWAuDQoyLiBUaGUgc2l6ZSBvZiBhIGdpdmVuIGRvdCBpcyBwcm9wb3J0aW9uYWwgdG8gaXQncyBgcG9wdWxhdGlvbmAgc2l6ZS4NCjMuIEhvdmVyIHRleHQgd2lsbCBhcHBlYXIgb3ZlciBhIGdpdmVuIHBvaW50IHdoaWNoIHdpbGwgZGlzcGxheSB0aGUgYGNvdW50cnkgbmFtZWAgYW5kIGBwb3B1bGF0aW9uYCBzaXplLiANCjQuIEFwcHJvcHJpYXRlIHVzZSBvZiBjb2xvciBhbmQgdHJhbnNwYXJlbmN5IGZvciB2aWV3aW5nIGVhc2UuDQpcDQpcDQoNCkZvciB0aGlzIGdyYXBoLCB3ZSB3aWxsIGFuYWx5emUgZGF0YSBvbmx5IGZyb20gdGhlIHllYXIgYDIwMTVgLiBXZSBjYW4gZXh0cmFjdCB0aGlzIGluZm9ybWF0aW9uIHZpYSB0aGUgZm9sbG93aW5nIGNvZGU6IA0KDQoNCmBgYHtyfQ0Kc3Vic2V0XzIwMTUgPC0gc3Vic2V0KGluaXRpYWxfZGF0YSwgWWVhciA9PSAyMDE1KQ0KYGBgDQpUaGUgcmVzdWx0aW5nIGRhdGEgZnJhbWUgb25seSBoYXMgMjAxNSBkYXRhOg0KYGBge3IgZWNobz1GQUxTRX0NCmhlYWQoc3Vic2V0XzIwMTUsIDUpDQpgYGANCg0KTm93LCBsZXQncyB2aWV3IHRoZSBpbnRlcmFjdGl2ZSBncmFwaCB3aGljaCBtZWV0cyB0aGUgc3BlY2lmaWNhdGlvbnMgbGlzdGVkIGFib3ZlLg0KDQpgYGB7cn0NCiMgQ3JlYXRlIHRoZSBzY2F0dGVyIHBsb3QNCnBsb3QgPC0gcGxvdF9seShkYXRhID0gc3Vic2V0XzIwMTUsDQogICAgICAgICAgICAgICAgeCA9IH5JbmNvbWUsDQogICAgICAgICAgICAgICAgeSA9IH5saWZlX2V4cGVjdGFuY3ksDQogICAgICAgICAgICAgICAgdGV4dCA9IH5wYXN0ZSgiQ291bnRyeTogIiwgQ291bnRyeSwgIjxicj5Qb3B1bGF0aW9uIFNpemU6ICIsIHBvcHVsYXRpb24pLA0KICAgICAgICAgICAgICAgIGNvbG9yID0gfkNvdW50cnksDQogICAgICAgICAgICAgICAgc2l6ZSA9IH5wb3B1bGF0aW9uLCBzaXplcyA9IGMoNSwgMTUwKSwgDQogICAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChvcGFjaXR5ID0gMC42LCBsaW5lID0gbGlzdChjb2xvciA9ICdibGFjaycsIHdpZHRoID0gMSkpKSAlPiUNCiAgICAgICAgbGF5b3V0KHRpdGxlID0gIkFzc29jaWF0aW9uIGJldHdlZW4gTGlmZSBFeHBlY3RhbmN5IGFuZCBJbmNvbWUgKDIwMTUpIiwNCiAgICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJJbmNvbWUiKSwNCiAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJMaWZlIEV4cGVjdGFuY3kiKSwNCiAgICAgICAgICAgICAgIGhvdmVybW9kZSA9ICJjbG9zZXN0IikNCg0KIyBTaG93IHRoZSBwbG90DQpwbG90DQpgYGANCjxpPjxmb250IHNpemU9Mj5OT1RFOiB0aGUgcHJvcG9ydGlvbmFsIHNpemUgb2YgdGhlIHBvaW50IGFuZCB0cmFuc3BhcmVuY3kgbGV2ZWxzIHdlcmUgY2hvc2VuIHZpYSB0cmlhbCBhbmQgZXJyb3IuIEFsc28sIGBob3Zlcm1vZGVgIGJlaW5nIHNldCB0byBgY2xvc2VzdGAgYWxsb3dzIHRoZSB1c2VyIHRvIGVhc2lseSB2aWV3IGNvdW50cnkgbWV0YWRhdGEgd2l0aG91dCB0aGUgY3Vyc29yIGJlaW5nIGV4YWN0bHkgb24gYSBnaXZlbiBtYXJrZXIuIFRoaXMgaXMgaGVscGZ1bCBiZWNhdXNlIHNvbWUgZG90cyBhcmUgcXVpdGUgc21hbGwuPC9mb250PjwvaT4NCg0KIyMgTmFycmF0aXZlIC0gMjAxNSBEYXRhDQpUaGUgaW50ZXJhY3RpdmUgZ3JhcGggaGFzIGFsbCB0aGUgZmVhdHVyZXMgd2UgZGlzY3Vzc2VkLiBUaGlzIGFsbG93cyB1cyB0byBlYXNpbHkgZGlzdGluZ3Vpc2ggd2hpY2ggY291bnRyaWVzIGhhdmUgdGhlIGhpZ2hlc3QgcG9wdWxhdGlvbi4gV2UgY2FuIGNsZWFybHkgc2VlIEluZGlhLCBDaGluYSwgYW5kIHRoZSBVU0EgaGF2aW5nIHZlcnkgbGFyZ2UgcG9wdWxhdGlvbnMgYmFzZWQgb24gdGhlIHNpemUgb2YgdGhlaXIgaW5kaXZpZHVhbCBtYXJrZXIuIEl0IGlzIGFsc28gZWFzeSB0byBzZWUgdGhhdCBKYXBhbiwgU3dpdHplcmxhbmQsIGFuZCBTaW5nYXBvcmUgYWxsIGhhdmUgdGhlIGhpZ2hlc3QgbGlmZSBleHBlY3RhbmN5LiBRYXRhciBoYXMsIGJ5IGZhciwgdGhlIG1vc3QgYW1vdW50IG9mIGF2ZyBpbmNvbWUgcGVyIHBlcnNvbjsgaXQgbXVzdCBiZSBuaWNlIHRvIGxpdmUgdGhlcmUuIEludGVyZXN0aW5nbHkgZW5vdWdoLCB0aGVyZSBkb2VzIDxpPm5vdDwvaT4gc2VlbSB0byBiZSBhIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGFtb3VudCBvZiBpbmNvbWUgYW4gaW5kaXZpZHVhbCBtYWtlcyBmb3IgYSBnaXZlbiBjb3VudHJ5LCBhbmQgdGhlIGxpZmUgZXhwZWN0YW5jeS4gSG93ZXZlciwgaXQgaXMgaW50ZXJlc3RpbmcgdG8gbm90ZSB0aGF0LCBnZW5lcmFsbHkgc3BlYWtpbmcsIHRoZSBBZnJpY2FuIGNvdW50cmllcyBoYXZlIHRoZSBsb3dlc3QgbGlmZSBleHBlY3RhbmN5LCB3aGlsZSB0aGUgQXNpYW4gY291bnRyaWVzIHNlZW0gdG8gaGF2ZSB0aGUgaGlnaGVzdC4NCg0KIyMgQW5pbWF0ZWQgR3JhcGgNCkluIHRoaXMgbmV4dCBzZWN0aW9uIHdlIHdpbGwgZGVtb25zdHJhdGUgaG93IHRvIHNob3cgYW4gYW5pbWF0aW9uIGZvciBzY2F0dGVyIHBsb3RzLiBXZSB3aWxsIHVzZSBvdXIgb3JpZ2luYWwgZGF0YSBzZXQgd2l0aCBhbGwgeWVhcnMgdXAgdG8gMTk1MCosIGFuZCBjeWNsZSB0aHJvdWdoIGVhY2ggeWVhciB0byBzZWUgaG93IHRoZSBkYXRhIGNoYW5nZXMgb3ZlciB0aW1lLiANCg0KPGk+PGZvbnQgc2l6ZT0xPipOb3RlOiB3ZSBpbmNsdWRlIHVwIHRvIDE5NTAgYmVjYXVzZSB0aGUgaW5jb21lIHN0YXJ0cyB0byBleHBvbmVudGlhbGx5IGluY3JlYXNlIGFmdGVyIHRob3NlIHllYXJzLiBUaGlzIGNhdXNlcyBmb3IgYSB2ZXJ5IHNrZXdlZCBhbmltYXRpb24gZm9yIHRoZSBmaXJzdCAxNTAgeWVhcnMuPC9pPjwvZm9udD4NCg0KVGhlIGFuaW1hdGVkIGdyYXBoIHdpbGwgaGF2ZSB0aGUgZm9sbG93aW5nIHNwZWNpZmljYXRpb25zOg0KDQoxLiBDeWNsZSB0aHJvdWdoIGVhY2ggYHllYXJgIGZyb20gMTgwMCB0byAxOTUwLg0KMi4gSGlnaGxpZ2h0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBgbGlmZSBleHBlY3RhbmN5YCBhbmQgYHBvcHVsYXRpb25gIHNpemUuDQozLiBVc2UgYSBjdXN0b20sIGNvbG9yLWJsaW5kIGZyaWVuZGx5IGNvbG9yIHBhbGV0dGUuDQo0LiBIYXZlIHRoZSBzaXplIG9mIGEgZ2l2ZW4gbWFya2VyIHByb3BvcnRpb25hbCB0byB0aGUgYHBvcHVsYXRpb25gIHNpemUuDQo1LiBQcm92aWRlIGFkZGl0aW9uYWwgbWV0YWRhdGEgd2hlbiBob3ZlcmluZyBvdmVyIGEgbWFya2VyLg0KDQpUaGUgY29kZSBpcyB2ZXJ5IHNpbWlsYXIgdG8gdGhlIHByZXZpb3VzIGludGVyYWN0aXZlIGdyYXBoLCB3aXRoIHRoZSBmb2xsb3dpbmcgYWRkaXRpb25zOg0KDQotIEEgbXVjaCBsYXJnZXIgaW5wdXQgZGF0YSBzZXQuDQotIEFkZCB0aGUgYmluZGluZyBmb3IgY3VzdG9tIGNvbG9ycw0KLSBDeWNsZSB0aHJvdWdoIHRoZSBgeWVhcmANCg0KUGxlYXNlIHZpZXcgdGhlIGNvZGUgJiBhbmltYXRlZCBwbG90IGJlbG93Og0KDQpgYGB7cn0NCnVwX3RvXzE5NTAgPC0gc3Vic2V0KGluaXRpYWxfZGF0YSwgWWVhciA8PSAxOTUwKQ0KDQpyZWdpb25fY29sb3JzIDwtIGMoIkFmcmljYSIgPSAiIzAwMDAwMCIsICJBbWVyaWNhcyI9IiNFNjlGMDAiLCAiQXNpYSI9IiM1NkI0RTkiLCAiRXVyb3BlIj0iIzAwOUU3MyIsICJPY2VhbmlhIj0iI0NDNzlBNyIpOw0KDQojIENyZWF0ZSB0aGUgYW5pbWF0ZWQgc2NhdHRlciBwbG90DQphbmltYXRlZF9wbG90IDwtIHBsb3RfbHkoZGF0YSA9IHVwX3RvXzE5NTAsDQogICAgICAgICAgICAgICAgeCA9IH5JbmNvbWUsDQogICAgICAgICAgICAgICAgeSA9IH5saWZlX2V4cGVjdGFuY3ksDQogICAgICAgICAgICAgICAgIyBJdGVyYXRlIHRocm91Z2ggZWFjaCB5ZWFyLg0KICAgICAgICAgICAgICAgIGZyYW1lID0gflllYXIsDQogICAgICAgICAgICAgICAgdGV4dCA9IH5wYXN0ZSgiQ291bnRyeTogIiwgQ291bnRyeSwgIjxicj5Qb3B1bGF0aW9uIFNpemU6ICIsIHBvcHVsYXRpb24pLA0KICAgICAgICAgICAgICAgIGNvbG9yID0gfnJlZ2lvbiwgDQogICAgICAgICAgICAgICAgIyBDdXN0b20gY29sb3ItYmxpbmQgZnJpZW5kbHkgY29sb3MuDQogICAgICAgICAgICAgICAgY29sb3JzID0gcmVnaW9uX2NvbG9ycywNCiAgICAgICAgICAgICAgICBzaXplID0gfnBvcHVsYXRpb24sIHNpemVzID0gYygxMCwgMTAwKSwgDQogICAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChvcGFjaXR5ID0gMC42LCBsaW5lID0gbGlzdChjb2xvciA9ICdibGFjaycsIHdpZHRoID0gMSkpKSAlPiUNCiAgICAgICAgbGF5b3V0KHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIExpZmUgRXhwZWN0YW5jeSBhbmQgSW5jb21lIE92ZXIgdGhlIFllYXJzIiwNCiAgICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJJbmNvbWUiKSwNCiAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJMaWZlIEV4cGVjdGFuY3kiKSwNCiAgICAgICAgICAgICAgIGhvdmVybW9kZSA9ICJjbG9zZXN0IikNCg0KIyBTaG93IHRoZSBwbG90DQphbmltYXRlZF9wbG90DQpgYGANCg0KIyMgTmFycmF0aW9uIC0gQW5pbWF0ZWQgUGxvdA0KRnJvbSAxODAwLTE5MDAgd2UgY2FuIHNlZSB0aGF0IHRoZSBsaWZlIGV4cGVjdGFuY3kgKH4yMC00MCkgYW5kIGluY29tZSAoPDIwaykgcmVhbGx5IGRvZXMgbm90IGNoYW5nZSB0aGF0IG11Y2ggZm9yIGEgZ2l2ZW4gcmVnaW9uLiBPZiBjb3Vyc2UsIHRoZXJlIGFyZSBhIGNvdXBsZSBvZiBleGNlcHRpb25zIGluIHRoZSBsYXRlIDE4MDBzIHdoZXJlIGEgZmV3IEV1cm9wZWFuIGNvdW50cmllcyBzdGFydCB0byBpbmNyZWFzZSB0aGVpciBhdmVyYWdlIGxpZmUgZXhwZWN0YW5jeSBpbnRvIHRoZSBtaWQgNTBzLiBXaGF0J3MgcmVhbGx5IGludGVyZXN0aW5nIGlzIGhvdyB0aGUgbGlmZSBleHBlY3RhbmN5IHN0YXJ0cyB0byBkcmFtYXRpY2FsbHkgaW5jcmVhc2UgaW4gdGhlIGVhcmx5IDE5MDAncyB3aXRoIHRoZSBpbnRyb2R1Y3Rpb24gb2YgcGVuaWNpbGxpbiBhbmQgbW9kZXJuIG1lZGljaW5lLiBJdCBpcyBubyBzdXJwcmlzZSB0aGF0IGZpcnN0IHdvcmxkIHJlZ2lvbnMgYXJlIHRoZSBmaXJzdCB0byBpbmNyZWFzZSB0aGVpciBsaWZlIGV4cGVjdGFuY3kgYXMgdGhleSBoYXZlIGFjY2VzcyB0byBtb3JlIGRvY3RvcnMgYW5kIG1vZGVybiBtZWRpY2luZSB0aGFuIGEgM3JkIHdvcmxkIHJlZ2lvbnMuDQpcDQpcDQpBIGZhc2NpbmF0aW5nIHBhdHRlcm4gZW1lcmdlcyBpZiB5b3UgZXhhbWluZSB0aGUgbGlmZSBleHBlY3RhbmN5IGZyb20gMTkxNSAtIDE5MjUuIFRoZSBhdmVyYWdlIGxpZmUgZXhwZWN0YW5jeSBkcm9wcyBmb3IgZXZlcnkgcmVnaW9uIGJ5IGEgbGFyZ2UgbWFyZ2luLiBUaGlzIGlzIGJlY2F1c2Ugb2YgV1cxLiBXZSBzZWUgYSBzaW1pbGFyIHBhdHRlcm4gZm9yIGxpZmUgZXhwZWN0YW5jeSBmcm9tIDE5MzAgLSAxOTUwIHdpdGggV1cyLiBJbml0aWFsbHksIGluIHRoZSBlYXJseSAxOTMwcywgb25seSBhIGZldyByZWdpb25zIGxvd2VyIHRoZWlyIGxpZmUgZXhwZWN0YW5jeSBiZWNhdXNlIG9mIHRoZSBpc29sYXRlZCBpbnZhc2lvbnMgb2YgR2VybWFueS4gSG93ZXZlciwgYnkgMTk0NCwgbWFueSByZWdpb25zIGRyb3AgZHJhbWF0aWNhbGx5LiANClwNClwNClRoaXMgZ29lcyB0byBzaG93IHRoYXQgd2FyIGhhcyBxdWl0ZSBhbiBlZmZlY3Qgb24gbGlmZSBleHBlY3RhbmN5IGNoYW5nZXMuIFRoaXMgbWFrZXMgYSBsb3Qgb2YgcHJhY3RpY2FsIHNlbnNlLg0K